package com.demo;

import gnu.io.CommPortIdentifier;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import gnu.io.UnsupportedCommOperationException;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;
import java.util.TooManyListenersException;
import java.util.concurrent.Delayed;
import java.util.regex.Matcher;
import java.util.regex.Pattern;



public class SerialPortUtils implements SerialPortEventListener {

    private CommPortIdentifier commPortId;

    private Enumeration<CommPortIdentifier> portList;

    private SerialPort serialPort;

    private InputStream inputStream;

    private OutputStream outputStream;

    private String data;

    private String dataHex;

    @SuppressWarnings("unchecked")
    public void init(ParamConfig paramConfig) throws CustomException {
        portList = CommPortIdentifier.getPortIdentifiers();
        boolean isExsist = false;
        while (portList.hasMoreElements()) {
            commPortId = portList.nextElement();
            if (commPortId.getPortType() == CommPortIdentifier.PORT_SERIAL) {
                if (paramConfig.getSerialNumber().equals(commPortId.getName())) {
                    isExsist = true;
                    try {
                        serialPort = (SerialPort) commPortId.open(Object.class.getSimpleName(), 2000);
                        serialPort.setSerialPortParams(paramConfig.getBaudRate(), paramConfig.getDataBit(),
                                paramConfig.getStopBit(), paramConfig.getCheckoutBit());
                    } catch (PortInUseException e) {
                        throw new CustomException("端口被占用");
                    } catch (UnsupportedCommOperationException e) {
                        throw new CustomException("不支持的COMM端口操作异常");
                    }
                    break;
                }
            }
        }
        if (!isExsist) {
            throw new CustomException("不存在该串口！");
        }
    }


    @Override
    public void serialEvent(SerialPortEvent event) {
        switch (event.getEventType()) {
            case SerialPortEvent.BI:
            case SerialPortEvent.OE:
            case SerialPortEvent.FE:
            case SerialPortEvent.PE:
            case SerialPortEvent.CD:
            case SerialPortEvent.CTS:
            case SerialPortEvent.DSR:
            case SerialPortEvent.RI:
            case SerialPortEvent.OUTPUT_BUFFER_EMPTY:
            case SerialPortEvent.DATA_AVAILABLE:
                try {
                    readComm();
                } catch (CustomException e) {
                    e.printStackTrace();
                }
                break;
            default:
                break;
        }
    }


    public String readComm() throws CustomException {
        try {
            inputStream = serialPort.getInputStream();
            byte[] readBuffer = new byte[inputStream.available()];
            int len = 0;
            while ((len = inputStream.read(readBuffer)) != -1) {
                data = new String(readBuffer, 0, len).trim();
                inputStream.close();
                inputStream = null;
                String p = "\\d+\\.\\d+";
                Pattern r = Pattern.compile(p);
                Matcher m = r.matcher(data);
                if (m.find()){
                    return m.group(0);
                }
            }
        } catch (IOException e) {
            throw new CustomException("读取串口数据时发生IO异常");
        }
        return null;
    }


    public void closeSerialPort() throws CustomException {
        if (serialPort != null) {
            serialPort.notifyOnDataAvailable(false);
            serialPort.removeEventListener();
            if (inputStream != null) {
                try {
                    inputStream.close();
                    inputStream = null;
                } catch (IOException e) {
                    throw new CustomException("关闭输入流时发生IO异常");
                }
            }
            if (outputStream != null) {
                try {
                    outputStream.close();
                    outputStream = null;
                } catch (IOException e) {
                    throw new CustomException("关闭输出流时发生IO异常");
                }
            }
            serialPort.close();
            serialPort = null;
        }
    }


    public void sendComm(String command) throws CustomException {

        try {
            outputStream = serialPort.getOutputStream();
            outputStream.write(command.getBytes(StandardCharsets.UTF_8));
            outputStream.flush();
        } catch (NullPointerException e) {
            throw new CustomException("找不到串口。");
        } catch (IOException e) {
            throw new CustomException("发送信息到串口时发生IO异常");
        }
    }


    public static byte[] charToByte(char c) {
        byte[] b = new byte[2];
        b[0] = (byte) ((c & 0xFF00) >> 8);
        b[1] = (byte) (c & 0xFF);
        return b;
    }
    /**
     * 串口返回值获取
     */
    public String getData() {
        String result = data;
        data = null;
        return result;
    }


    public static void main(String[] args) throws CustomException, InterruptedException {
        SerialPortUtils serialPort = new SerialPortUtils();
        ParamConfig paramConfig = new ParamConfig("COM3", 9600, 0, 8, 1);
        serialPort.init(paramConfig);
        while (true){
            serialPort.sendComm("open");
            Thread.sleep(2000);
            serialPort.sendComm("stop");
            Thread.sleep(2000);
        }
        //serialPort.sendComm('1');
//        while (true){
//            String data = serialPort.readComm();
//            String p = "\\d+\\.\\d+";
//            Pattern r = Pattern.compile(p);
//            Matcher m = r.matcher(data);
//            if (m.find()){
//                String s = m.group(0);
//                System.out.println(m.group(0));
//            }
//            Thread.sleep(200);
//        }
        //serialPort.closeSerialPort();
    }
}